"""
主题: 循环引用数据结构的内存管理
问题: 你的程序创建了很多循环引用数据结构(比如树、图、观察者模式等)，你碰到了内存管理难题。
提示 : 
"""

import weakref


class Node:
    def __init__(self, value):
        self.value = value
        self._parent = None
        self.children = []

    def __repr__(self):
        return 'Node({!r:})'.format(self.value)

    # property that manages the parent as a weak-reference
    @property
    def parent(self):
        return None if self._parent is None else self._parent()

    @parent.setter
    def parent(self, node):
        self._parent = weakref.ref(node)

    def add_child(self, child):
        self.children.append(child)
        child.parent = self

# Class just to illustrate when deletion occurs
class Data:
    def __del__(self):
        print('Data.__del__')

# Node class involving a cycle
class Node1:
    def __init__(self):
        self.data = Data()
        self.parent = None
        self.children = []

    def add_child(self, child):
        self.children.append(child)
        child.parent = self

# Node class involving a cycle
class Node2:
    def __init__(self):
        self.data = Data()
        self.parent = None
        self.children = []

    def add_child(self, child):
        self.children.append(child)
        child.parent = self

    # NEVER DEFINE LIKE THIS.
    # Only here to illustrate pathological behavior
    def __del__(self):
        del self.data
        del self.parent
        del self.children

def recipe1():
    root = Node('parent')
    c1 = Node('child')
    root.add_child(c1)

    print(f"{c1.parent = }")
    del root
    print(f"{c1.parent = }")

def recipe2():
    '''垃圾回收试验'''
    a = Data()
    del a
    # print(a) NameError: name 'a' is not defined
    a = Node1()
    del a
    # print(a)
    a = Node1()
    a.add_child(Node1())
    print('--------last del start------------')
    del a  # Not deleted (no message)
    print('--------last del end------------')
    # print(a) 
    print('-----------------------------')

def recipe3():
    '''导致内存泄露'''
    a = Node2()
    a.add_child(Node2())
    del a

    print('--------gc.collect()------------')
    import gc
    gc.collect()
    
def main():
    print('recipe1'.center(20, '*'))
    recipe1()
    print('recipe2'.center(20, '*'))
    recipe2()
    print('recipe3'.center(20, '*'))
    recipe3()

if __name__ == '__main__':
    main()         